package socket

import (
	"errors"
	"runtime/debug"

	"qmp_go_push/pkg/logger"

	"github.com/gorilla/websocket"
	"go.uber.org/zap"
)

const (
	heartbeatExpirationTime = 60
)

// Client 用户连接
type Client struct {
	UserID        string
	Conn          *websocket.Conn // 用户连接
	Send          chan []byte     // 待发送的数据
	Addr          string          // 客户端地址
	FirstTime     uint64          // 首次连接事件
	HeartbeatTime uint64          // 用户上次心跳时间
}

// NewClient 初始化
func NewClient(addr string, conn *websocket.Conn, firstTime uint64, userID string) *Client {
	return &Client{
		UserID:        userID,
		Conn:          conn,
		Send:          make(chan []byte, 100),
		Addr:          addr,
		FirstTime:     firstTime,
		HeartbeatTime: firstTime,
	}
}

// 读取客户端数据
func (c *Client) read() {
	defer func() {
		if r := recover(); r != nil {
			logger.Error(logger.ErrLogger, "socket read", zap.Any("stack", string(debug.Stack())))
		}
	}()
	defer func() {
		logger.Error(logger.ErrLogger, "socket read", zap.String("userID", c.UserID), zap.Error(errors.New("client读取客户端数据 关闭conn")))
		close(c.Send)
	}()
	for {
		_, message, err := c.Conn.ReadMessage()
		if err != nil {
			logger.Info(logger.BizLogger, "socket read", zap.String("userID", c.UserID), zap.Error(err))
			return
		}

		// 处理程序
		// 处理具体业务逻辑
		logger.Info(logger.BizLogger, "socket read", zap.String("userID", c.UserID), zap.Any("data", string(message)))
		HandleFunc(c, message)
	}
}

// 向客户端写数据
func (c *Client) write() {
	defer func() {
		if r := recover(); r != nil {
			logger.Error(logger.ErrLogger, "socket write", zap.Any("stack", string(debug.Stack())))
		}
	}()
	defer func() {
		logger.Error(logger.ErrLogger, "socket write", zap.String("userID", c.UserID), zap.Error(errors.New("client发送数据给客户端 关闭conn")))
		clientManager.DelUsers(c)
		_ = c.Conn.Close()
	}()
	for {
		select {
		case message, ok := <-c.Send:
			if !ok {
				logger.Info(logger.BizLogger, "socket write", zap.String("userID", c.UserID), zap.Error(errors.New("client.send chan 待发数据异常")))
				return
			}
			_ = c.Conn.WriteMessage(websocket.TextMessage, message)
		}
	}
}

// SendMsg 发送数据
func (c *Client) SendMsg(msg []byte) {
	if c == nil {
		return
	}
	defer func() {
		if r := recover(); r != nil {
			logger.Error(logger.ErrLogger, "SendMsg", zap.Any("stack", string(debug.Stack())))
		}
	}()
	c.Send <- msg
}

func (c *Client) SetHeartbeat(currentTime uint64) {
	c.HeartbeatTime = currentTime
	return
}

// IsHeartbeatTimeout 心跳超时
func (c *Client) IsHeartbeatTimeout(currentTime uint64) (timeout bool) {
	if c.HeartbeatTime+heartbeatExpirationTime <= currentTime {
		timeout = true
	}
	return
}
